home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / System 7.0 Samples / Edition Manager / Subscribe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-18  |  53.4 KB  |  1,132 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  *
  3.  *  Apple Developer Technical Support
  4.  *
  5.  *  Edition subscribing routines
  6.  *
  7.  *  Program:    EditionSample
  8.  *  File:       Subscribe.c -   C Source
  9.  *
  10.  *  by:         C.K. Haun <TR>
  11.  *
  12.  *  Copyright © 1990,1991 Apple Computer, Inc.
  13.  *  All rights reserved.
  14.  *
  15.  *------------------------------------------------------------------------------
  16.  * This file handles the Subscribe section of the program.  It also handles some of 
  17.  * the common use routines, like the section options dialog.
  18.  *----------------------------------------------------------------------------*/
  19.  
  20. #define __SUBSCRIBE__
  21.  
  22. #pragma segment Subscribe
  23. #pragma load "EdSampheaders"                                /* see the Buildheaders.c file */
  24.  
  25. #include "EdSampdefines.h"
  26. /* prototypes */
  27. OSErr MyReadSection(SectionHandle theSection);
  28.  
  29. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow);
  30. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch);
  31. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec);
  32. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn);
  33. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
  34. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
  35. void PasteSubscription(void);
  36. void CutSubscription(void);
  37. void CopySubscription(void);
  38. void KillClipSub(void);
  39.  
  40. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum);
  41. void SkipOverSubscriber(windowCHandle inWindow, unsigned short theKey);
  42. extern pascal short ExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
  43. extern pascal Boolean ExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
  44.  
  45. /* external references */
  46. extern WindowPtr gActionWindows;
  47. extern WindowPtr gCurrentWindow;
  48. extern WindowPtr gClipWindowPtr;
  49. extern short gWindowCount;
  50. extern OSErr MyUpdateEdition(SectionHandle theSection);
  51. extern OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection);
  52. extern unsigned long gSectionID;
  53. extern void ShowMe(Str255 in, OSErr aevtErr);
  54. extern void MyCancelPublication(SectionHandle inSection);
  55. extern WindowPtr FindSection(SectionHandle inSection);
  56. extern void CheckTextSections(windowCHandle inWindow, short Action);
  57. extern Boolean gShowPub;
  58. extern Boolean gShowSub;
  59. extern Boolean gExpanded;
  60. extern Boolean gResizeSub;
  61. extern short gClipHasContents;
  62. extern SectionHandle gClipSection;
  63. extern PicHandle gClipPict;
  64. extern Handle gScrapData;
  65. extern EditionOpenerProcPtr gOriginalOpener;
  66. extern void ReadDocData(windowCHandle newWindControl, short readRefNum);
  67. extern WindowPtr AddNewWindow(Boolean showIt);
  68. extern OSErr MySetHandleSize(Handle theHandle, Size theSize);
  69. extern void RePackText(textSectionHandle currentSection, TEHandle theTEHandle);
  70. extern textSectionHandle GetTextSection(windowCHandle shortName, SectionType what);
  71. extern textSectionHandle TextSectionFromSecHandle(SectionHandle theSection);
  72.  
  73. /* this point tells EM to center our expanded box, if we're using that feature */
  74. Point expPoint = 
  75. {
  76.     -1, -1
  77. };
  78.  
  79.  
  80.  
  81.  
  82. /* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
  83. /* subscribe to a PICT type edition, anywhere, anytime.  It also stores the */
  84. /* section handle returned in the window data structure for the current window */
  85. /* You can only subscribe to TEXT if you have a text box open in the current window.  */
  86. /* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
  87. /* subscribe to that as such, same as you would with clipboard types. */
  88.  
  89. void DoSubscribe(void)
  90. {
  91.     OSErr myErr;
  92.     SectionHandle secHandle;
  93.     windowCHandle shortName;
  94.     NewSubscriberReply GetSub;
  95.     shortName = (windowCHandle)GetWRefCon(gCurrentWindow);      /* get our struct */
  96.     GetSub.formatsMask = kPICTformatMask;                   /* tell the dialog we only want PICT type editions */
  97.     if ((*shortName)->boxHandle != nil)                     /* is there a text box already? */
  98.         GetSub.formatsMask += kTEXTformatMask;
  99.     /* GetLastEditionContainerUsed gives you either the last edition container used  */
  100.     /* (either pub or sub, since they are the same to the Edition Manager) or if there */
  101.     /* was not a previous container, it fills it with a default container. */
  102.     GetLastEditionContainerUsed(&GetSub.container);
  103.     /* Now ask the user to select an edition to subscribe to */
  104.     if (!gExpanded)
  105.         myErr = NewSubscriberDialog(&GetSub);
  106.     else
  107.     {
  108.         ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
  109.         ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
  110.         myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
  111.         DisposeRoutineDescriptor(mfUPP);
  112.         DisposeRoutineDescriptor(dhUPP);
  113.     }
  114.  
  115.     if (myErr != noErr) {                                   /* bail on fail */
  116.         ShowMe("\pNewSubscriberDialog", myErr);
  117.         return;
  118.     }
  119.     if (GetSub.canceled)                                    /* did they cancel the dialog? */
  120.         return;
  121.     HLock((Handle)shortName);
  122.     /* Now create a new section record for the container the user picked.  In other words, the */
  123.     /* Edition manager keeps track of things by the container, and will give you a section */
  124.     /* record that refers to it for you to keep track with.  */
  125.     /* ••• NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
  126.     /* it came out of your heap, and YOU are responsible for disposing of it when you are */
  127.     /* completely done (and have UnRegistered) the section.  If you're not careful about this */
  128.     /* then you'll get creeping memory loss.  */
  129.     /* Now see if the window has ever been saved.  If so, we can store a reference to */
  130.     /* the file in the section */
  131.     if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
  132.         myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
  133.     } else {
  134.         /* if the file has been saved once, then we can store a reference to the 'parent' file */
  135.         /* in the edition */
  136.         FSSpec tempSpec;
  137.         Boolean myWasChanged;
  138.         myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
  139.         myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
  140.                            &secHandle);
  141.     }
  142.     if (myErr != noErr) {
  143.         ShowMe("\pNewSection", myErr);
  144.         return;
  145.     }
  146.     /* section successfully gotten.  Add it to the current window section list please */
  147.     /* Handle this in whatever way is appropriate for your application, of course.  */
  148.     /* The main point to remember is that you _must_ keep track of the section handles, */
  149.     /* they are your method (only method) for comunication between your application */
  150.     /* and the Edition Manager, you will be passing sections to the EM, and it will be */
  151.     /* passing them back to you. */
  152.     gSectionID++;                                           /* increment our unique ID */
  153.     StoreSubscriber(shortName, secHandle, nil, nil);
  154.     HUnlock((Handle)shortName);
  155. }
  156.  
  157. /* end DoSubscribe */
  158. /* DoOptions handles the SectionOptions menu selection.  The handle passed */
  159. /* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
  160. /* out what dialog to display by looking at the section record */
  161. /* ••• BE CAREFUL with the section  handle you pass to the options dialog (or anywhere, for that matter) */
  162. /* A section that has not been registered, or a section containing a bad alias handle, will */
  163. /* cause the options dialog to blow up in unusual and fun ways */
  164. /* This call also includes the expanded section options dialog box with one */
  165. /* extra item, to show how it's used. */
  166. void DoOptions(SectionHandle inSection)
  167. {
  168.     OSErr myErr;
  169.     SectionOptionsReply oreply;
  170.     Boolean subExpansion;
  171.     
  172.     oreply.sectionH = inSection;                            /* put the section passed in the reply record */
  173.     if ((*inSection)->kind == stSubscriber)
  174.         subExpansion = true;
  175.     else
  176.         subExpansion = false;
  177.     myErr = IsRegisteredSection(inSection);
  178.     if (myErr != noErr) {
  179.         ShowMe("\p Bad Section ", myErr);
  180.         return;
  181.     }
  182.     if (subExpansion) {
  183.         ExpDlgHookUPP dhUPP = NewExpDlgHookProc(SubExpOptHook);
  184.         ExpModalFilterUPP mfUPP = NewExpModalFilterProc(SubExpOptFilter);
  185.         myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, dhUPP, mfUPP, nil);
  186.         DisposeRoutineDescriptor(dhUPP);
  187.         DisposeRoutineDescriptor(mfUPP);
  188.     } else {
  189.         if (!gExpanded)
  190.             myErr = SectionOptionsDialog(&oreply);          /* run the dialog */
  191.         else
  192.         {
  193.             ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
  194.             ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
  195.             myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
  196.             DisposeRoutineDescriptor(dhUPP);
  197.             DisposeRoutineDescriptor(mfUPP);
  198.         }
  199.     }
  200.     if (myErr != noErr) {
  201.         ShowMe("\pSection Options", myErr);
  202.         return;
  203.     }
  204.     if (oreply.canceled)                                    /* if user canceled */
  205.         return;
  206.     if (oreply.action == sectionReadMsgID) {
  207.         /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
  208.         /* one that gets called on a sect read AppleEvent */
  209.         MyReadSection(inSection);
  210.     } else {
  211.         if (oreply.action == sectionWriteMsgID) {
  212.             /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
  213.             /* one that gets called on a sect writ AppleEvent */
  214.             MyUpdateEdition(inSection);
  215.         } else {
  216.             if (oreply.action == 'goto') {
  217.                 /* this is the sect scrl (section scroll) event from the dialog */
  218.                 /* the dialog has already taken the action for you, that's it's job */
  219.             } else {
  220.                 if (oreply.action == emCancelSectionDialogRefCon) {
  221.                     /* This is for canceling a section, either pub or sub, you have to make the */
  222.                     /* choice based on what the section is */
  223.                     SectionType tempST;
  224.                     HLock((Handle)inSection);
  225.                     tempST = (*inSection)->kind;            /* what kinda thing is this? */
  226.                     HUnlock((Handle)inSection);
  227.                     
  228.                     MyCancelSection(inSection, FindSection(inSection));
  229.                 }
  230.             }
  231.         }
  232.     }
  233. }
  234.  
  235. /* end DoOptions */
  236.  
  237. /* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
  238. /* AppleEvents of the type 'sect' 'read'.  What this means is that whenever I get a */
  239. /* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
  240. /* call AEProcessAppleEvent (in AppleEventM.c).   This is where the actual section data */
  241. /* gets read in, when the Edition Manager tells you the edition is ready to read */
  242. pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  243. {
  244. #pragma unused (reply,refIn)
  245.     SectionHandle theSection;
  246.     OSErr myErr;
  247.     
  248.     myErr = GetSectionHandleFromEvent(messagein, &theSection);      /* in AppleEventM.c */
  249.     if (myErr) {
  250.         ShowMe("\pGetSectionHandleFromEvent", myErr);
  251.         return(myErr);
  252.     }
  253.     /* This next step is very important.  Unexpected things can happen to you, */
  254.     /* a section could disappear between the time an event gets posted and when it */
  255.     /* finally gets to your application (particularly since AppleEvents are the lowest in */
  256.     /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
  257.     /* whatever.  You must make a current check with the EM to see if the section that */
  258.     /* you are supposed to read. */
  259.     myErr = IsRegisteredSection((SectionHandle)theSection);
  260.     if (myErr) {
  261.         ShowMe("\pRead IsRegisteredSection", myErr);
  262.         return(myErr);
  263.     }
  264.     /* It is a valid section.  Jump to my routine that opens and reads it */
  265.     MyReadSection(theSection);
  266. }
  267.  
  268. /* end AEReadSectionHandler */
  269.  
  270. /* MyReadSection opens and reads the edition data into my window data structure. */
  271. OSErr MyReadSection(SectionHandle theSection)
  272. {
  273.     OSErr readErr;
  274.     OSErr myErr;
  275.     EditionRefNum sRefNum;
  276.     Size dataSize;
  277.     Boolean existed = false;                                /* for setting the display rect */
  278.     /* open the edition and get a ref number */
  279.     SetCursor(*GetCursor(watchCursor));
  280.     myErr = OpenEdition(theSection, &sRefNum);
  281.     if (myErr) {
  282.         ShowMe("\pOpenEdition", myErr);
  283.         return(myErr);
  284.     }
  285.     /* Here we are double-checking the edition.  I'm first checking for PICT data, */
  286.     /* and as a handy side effect, it gives us the size of the data (returned in my */
  287.     /* variable dataSize) for us to use when we read it later */
  288.     if (noErr == (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))) {
  289.         /* It does have a pict, read it in */
  290.         register qq, jj;                                    /* loop vars for window search */
  291.         long subIDtofind;
  292.         
  293.         /*  There is already a handle allocated for this picture in the window structure. 
  294.         *   Find it, resize it (since the edition size could have changed) and fill it.
  295.         *       Keep in mind that the section read may happen for a window which is not 
  296.         *       frontmost, so we need to search all the windows to find the ID */
  297.         WindowPtr tempPort;
  298.         Boolean secFound = false;
  299.         SectionHandle *tempPtr;
  300.         SectionRecord *tempRecord;
  301.         Handle tempHandle;
  302.         WindowPtr tempNextWindow;
  303.         Rect *tempRect;
  304.         Rect holdRect;
  305.         Boolean isClip;
  306.         HLock((Handle)theSection);
  307.         subIDtofind = (*theSection)->sectionID;             /* what ID are we reading?  */
  308.         /* check to see if this is the clipboard's section.  If so, let the clipboard */
  309.         /* handle it */
  310.         if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil))
  311.             return(ReadClipSection(dataSize, sRefNum));
  312.         GetPort(&tempPort);                                 /* save the current port */
  313.         /* search window list now */
  314.         tempNextWindow = gActionWindows;                    /* start at the beginning of the chain */
  315.         for (qq = 0; qq < gWindowCount; qq++) {
  316.             windowCHandle tempWC;
  317.             /* do housekeeping to get to the section handle list */
  318.             tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
  319.             HLock((Handle)tempWC);
  320.             tempHandle = (*tempWC)->subs;                   /* handle containing SectionHandles */
  321.             HLock(tempHandle);
  322.             tempPtr = (SectionHandle *)*tempHandle;
  323.             /* Loop through all our sections until we find this edition */
  324.             for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
  325.                 Handle *newTemp;
  326.                 HLock((Handle)*tempPtr);
  327.                 tempRecord = *(*tempPtr);
  328.                 if (tempRecord->sectionID == subIDtofind) {
  329.                     /* found the section belonging to this read. */
  330.                     /* can't break, since it is conceiveable that the user has more that one subscription in this document */
  331.                     SetPort(tempNextWindow);                /* set the port to the window we found the section in */
  332.                     HLock((*tempWC)->subDataHandle);
  333.                     newTemp = (Handle *)*((*tempWC)->subDataHandle);
  334.                     newTemp += jj;
  335.                     /* if the dataSize returned was -1 then the size was unknown when opened.  */
  336.                     /* in this case, this should only happen with our special opener.  */
  337.                     /* So, if it is -1, then we'll have to handle the read */
  338.                     /* in a series of steps to get the right amount of data */
  339.                     /* For now, I'll leave that out until I put in a custom */
  340.                     /* opener. Watch this space */
  341.                     if (dataSize != -1) {
  342.                         HUnlock(*newTemp);
  343.                         MySetHandleSize(*newTemp, dataSize);
  344.                         HLock(*newTemp);
  345.                     }
  346.                     /* read the pict in */
  347.                     myErr = MyReadEditionData(**newTemp, 'PICT', sRefNum, &dataSize);
  348.                     /* ••••• NOTE: After much discussion with our Human Interface folks and the */
  349.                     /* Edition Manager engineer, we've decided that the interface guidelines */
  350.                     /* for editions will say that reading a subscription does _not_ dirty */
  351.                     /* a document.  A lot of soul-searching went on to make this decision, and */
  352.                     /* we decided this way primarily to keep the user from getting confused.  */
  353.                     /* Editions should be as transparent and automatic as possible, and reminding */
  354.                     /* the user that an edition is a 'special' thing that they have to do */
  355.                     /* unusual things with to make work right will remove some of that */
  356.                     /* automation.  Of course, the 'cached' version of the subscription that */
  357.                     /* you save with the document should be updated when the subscription changes */
  358.                     /* So, the following line was commented out. */
  359.                     /* (*tempWC)->windowDirty = true;  */
  360.                     /* mark window dirty on every read */
  361.                     holdRect = (*(PicHandle)(*newTemp))->picFrame;
  362.                     HUnlock(*newTemp);
  363.                     /* put the picture in the corner, if it didn't exist.  If it did, adjust the rect as
  364.                     *   required */
  365.                     HLock((*tempWC)->subRects);
  366.                     newTemp = (Handle *)*((*tempWC)->subRects);
  367.                     newTemp += jj;
  368.                     /* if the handle is the size of a rect, I've seen this edition before */
  369.                     if (GetHandleSize(*newTemp) == sizeof(Rect)) {
  370.                         existed = true;                     /* it's already been made */
  371.                     } else {
  372.                         HUnlock(*newTemp);
  373.                         MySetHandleSize(*newTemp, sizeof(Rect));        /* new subscription */
  374.                     }
  375.                     HLock(*newTemp);
  376.                     tempRect = (Rect *)*(*newTemp);
  377.                     if (!existed) {
  378.                         tempRect->top = tempRect->left = 0;
  379.                         tempRect->bottom = holdRect.bottom - holdRect.top;
  380.                         tempRect->right = holdRect.right - holdRect.left;
  381.                     } else {
  382.                         InvalRect(tempRect);                /* refresh the old image if the thing was resized */
  383.                         /*          tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
  384.                                   tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
  385.                           */
  386.                     }
  387.                     InvalRect(tempRect);
  388.                     HUnlock(*newTemp);
  389.                     HUnlock((Handle)*tempPtr);
  390.                     
  391.                 } else {
  392.                     HUnlock((Handle)*tempPtr);
  393.                     tempPtr += 1;
  394.                 }
  395.             }                                               /* section handle loop jj */
  396.             tempNextWindow = (*tempWC)->nextWindow;
  397.             HUnlock(tempHandle);
  398.             HUnlock((Handle)tempWC);
  399.             if (tempNextWindow == nil)
  400.                 break;
  401.             
  402.             /* ••• NOTE: You'll notice that there is no break or exit from this section searching loop */
  403.             /* Why?  Because there may be many subscribers to the same edition.  The user may */
  404.             /* have multiple subscribtions in the same window, or in any of his or her windows. */
  405.             /* Don't assume that there is only one subscriber (unless you require it, which may be */
  406.             /* reasonable for a single document but _not_ for a multi-document application), run */
  407.             /* your whole list each time to be certain everything gets refreshed */
  408.         }                                                   /* window loop qq */
  409.         SetPort(tempPort);                                  /* reset the port to what it was when we entered */
  410.     } else {
  411.         if (noErr == (myErr = EditionHasFormat(sRefNum, 'TEXT', &dataSize))) {
  412.             WindowPtr theWindow;
  413.             windowCHandle tempWC;
  414.             TEHandle tempTEH;
  415.             textSectionHandle theTES;
  416.             long tempStart, tempEnd;
  417.             /* it's a text subscription.  That means we search in the text path, and also need */
  418.             /* to update the TEHandle for the window this goes with */
  419.             theWindow = FindSection(theSection);
  420.             theTES = TextSectionFromSecHandle(theSection);
  421.             HLock((Handle)theTES);
  422.             tempWC = (windowCHandle)GetWRefCon(theWindow);
  423.             tempTEH = (*tempWC)->boxHandle;
  424.             /* save the current TE selection range so that the user is returned to the */
  425.             /* place he or she was before we did the reading, so the text doesn't jump */
  426.             /* around all loony on them */
  427.             tempStart = (*tempTEH)->selStart;
  428.             tempEnd = (*tempTEH)->selEnd;
  429.             
  430.             /* first thing we need to do is remove whatever the current sub data in our */
  431.             /* TE Record is.  if there is any, o'course */
  432.             if ((*theTES)->startChar != (*theTES)->endChar) {
  433.                 TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
  434.                 TEDelete(tempTEH);
  435.             }
  436.             SetHandleSize((*theTES)->theText, dataSize);
  437.             HLock((*theTES)->theText);
  438.             MyReadEditionData(*(*theTES)->theText, 'TEXT', sRefNum, &dataSize);
  439.             /* that gives us the text.  Now we need to adjust our endpoint */
  440.             (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
  441.             /* set insertion point to where we want to be */
  442.             TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
  443.             TEInsert(*(*theTES)->theText, dataSize, tempTEH);
  444.             HUnlock((*theTES)->theText);
  445.             HUnlock((Handle)theTES);
  446.             /* reset insertion point to what it once was */
  447.             TESetSelect(tempStart, tempEnd, tempTEH);
  448.         }
  449.     }
  450. }
  451.  
  452. /* end MyReadSection */
  453.  
  454. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
  455. {
  456.     OSErr myErr;
  457.     if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
  458.         CloseEdition(readRef, false);
  459.     else
  460.         CloseEdition(readRef, true);
  461.     return(myErr);
  462. }
  463.  
  464. /*  HandleSectionSave handles saving and closing of subscribers for
  465. *       a document.  The Boolean flags tell this function wheither to write
  466. *       ouut the data (on save or save/close) and weither to UnRegister
  467. *       the sections (on close).
  468. *       The resource fork is open on entry.
  469. */
  470. /* theWind is locked on entry */
  471. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
  472. {
  473.     SectionHandle *theSections;
  474.     Handle *newTemp;
  475.     SectionRecord secRec;
  476.     Handle tempHandle;
  477.     Rect *tempRectPtr;
  478.     register qq;
  479.     OSErr myErr;
  480.     if ((*theWind)->numSubs) {
  481.         Handle *tempPictPtr;
  482.         HLock((*theWind)->subs);
  483.         theSections = (SectionHandle *)*(*theWind)->subs;
  484.         /* and display rectangles */
  485.         HLock((*theWind)->subRects);
  486.         HLock((*theWind)->subDataHandle);
  487.         newTemp = (Handle *)*((*theWind)->subRects);
  488.         tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
  489.         /* loop through the sections */
  490.         for (qq = 0; qq < (*theWind)->numSubs; qq++) {
  491.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  492.             AssociateSection(*theSections, theSpec);
  493.             /* write the section handle out... */
  494.             if (writeEm) {
  495.                 tempHandle = (Handle)*theSections;
  496.                 HandToHand(&tempHandle);
  497.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  498.                 secRec = *(*(*theSections));                /* just for easier display below */
  499.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  500.                 /* now do the same with the alias record please */
  501.                 tempHandle = (Handle)secRec.alias;
  502.                 HandToHand(&tempHandle);
  503.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  504.                 HUnlock((Handle)*theSections);
  505.                 /* save off the display rect for this sub */
  506.                 tempHandle = *newTemp;
  507.                 HandToHand(&tempHandle);
  508.                 AddResource(tempHandle, 'RECT', secRec.sectionID, "");
  509.                 /* and save out the picture data, so we don't need to immediatly do a */
  510.                 /* section read when the file is opened */
  511.                 tempHandle = *tempPictPtr;
  512.                 HandToHand(&tempHandle);
  513.                 AddResource(tempHandle, 'PICT', secRec.sectionID, "");
  514.             }                                               /* writeEm if */
  515.             
  516.             if (dereg) {
  517.                 UnRegisterSection(*theSections);
  518.                 /* and dispose of the alias handle */
  519.                 DisposeHandle((Handle)*(*(*theSections))->alias);
  520.                 /* and the section handle */
  521.                 DisposeHandle((Handle)*theSections);
  522.                 /* and the rectangle handle */
  523.                 DisposeHandle((Handle)*newTemp);
  524.                 /* picture handle disposed in closewindow */
  525.             }
  526.             theSections += 1;                               /* go to next section handle please */
  527.             newTemp += 1;                                   /* and next rectangle */
  528.         }
  529.         HUnlock((*theWind)->subRects);
  530.         HUnlock((*theWind)->subs);
  531.     }                                                       /* end subscriber save section */
  532.     /* now do the same thing for our publishers please */
  533.     /* Of course, here you'll also write the data if pumAutomatic is set */
  534.     
  535.     if ((*theWind)->numPubs) {
  536.         HLock((*theWind)->pubs);
  537.         theSections = (SectionHandle *)*(*theWind)->pubs;
  538.         /* and display rectangles */
  539.         HLock((*theWind)->pubRects);
  540.         tempRectPtr = (Rect *)*((*theWind)->pubRects);
  541.         
  542.         /* loop through the sections */
  543.         for (qq = 0; qq < (*theWind)->numPubs; qq++) {
  544.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  545.             AssociateSection(*theSections, theSpec);
  546.             /* write the section handle out... */
  547.             if (writeEm) {
  548.                 tempHandle = (Handle)*theSections;
  549.                 HandToHand(&tempHandle);
  550.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  551.                 secRec = *(*(*theSections));                /* just for easier display below */
  552.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  553.                 /* now do the same with the alias record please */
  554.                 tempHandle = (Handle)secRec.alias;
  555.                 HandToHand(&tempHandle);
  556.                 
  557.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  558.                 HUnlock((Handle)*theSections);
  559.                 /* save off the display rect for this pub */
  560.                 
  561.                 tempHandle = NewHandle(sizeof(Rect));
  562.                 PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
  563.                 HandToHand(&tempHandle);
  564.                 AddResource(tempHandle, 'RECT', secRec.sectionID, "");
  565.                 if (secRec.mode == pumOnSave) {
  566.                     MyUpdateEdition(*theSections);
  567.                     /* and indicate that this was saved with a document */
  568.                     (*(*theSections))->refCon |= kSavedOnce;        /* OR in our saved flag with type */
  569.                 }
  570.             }                                               /* writeEm if for pubs */
  571.             
  572.             if (dereg) {
  573.                 UnRegisterSection(*theSections);
  574.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  575.                 /* then we'll delete it.  */
  576.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
  577.                     OSErr myErr;
  578.                     FSSpec deleteSpec;
  579.                     Boolean myWasChanged;
  580.                     ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
  581.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  582.                         ShowMe("\pDelete Editon", myErr);
  583.                     }
  584.                 }
  585.                 
  586.                 /* and dispose of the alias handle */
  587.                 DisposeHandle((Handle)*(*(*theSections))->alias);
  588.                 /* and the section handle */
  589.                 DisposeHandle((Handle)*theSections);
  590.                 
  591.             }
  592.             theSections += 1;                               /* go to next section handle please */
  593.             tempRectPtr += 1;                               /* and next rectangle */
  594.         }
  595.         HUnlock((*theWind)->pubRects);
  596.         HUnlock((*theWind)->pubs);
  597.     }
  598.     /* now save off any text sections in this document */
  599.     if ((*theWind)->textSections) {
  600.         textSectionHandle tempTS = (*theWind)->textSections;
  601.         do {
  602.             tempHandle = (Handle)(*tempTS)->theSection;
  603.             /* make sure the text is the latest */
  604.             RePackText(tempTS, (*theWind)->boxHandle);
  605.             AssociateSection((SectionHandle)tempHandle, theSpec);
  606.             
  607.             if (writeEm) {
  608.                 HandToHand(&tempHandle);
  609.                 myErr = MemError();
  610.                 if (myErr)
  611.                     ShowMe("\p memerr", myErr);
  612.                 HLock(tempHandle);                          /* lock down the original section so we can work with it */
  613.                 secRec = *(*(SectionHandle)tempHandle);     /* just for easier display below */
  614.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  615.                 /* save the alias */
  616.                 tempHandle = (Handle)secRec.alias;
  617.                 HandToHand(&tempHandle);
  618.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  619.                 /* now save a copy of my whole text record */
  620.                 
  621.                 tempHandle = (Handle)tempTS;
  622.                 HandToHand(&tempHandle);
  623.                 /* use the same ID number as the section, make things easy */
  624.                 /* zap any forward link in this, so StoreSection doesn't get */
  625.                 /* confused when the section is read back in */
  626.                 (*(textSectionHandle)tempHandle)->nextSection = nil;
  627.                 (*(textSectionHandle)tempHandle)->theText = nil;
  628.                 (*(textSectionHandle)tempHandle)->theSection = nil;
  629.                 AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
  630.                 
  631.                 /* and finally, the associated text */
  632.                 tempHandle = (*tempTS)->theText;
  633.                 HandToHand(&tempHandle);
  634.                 AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
  635.                 if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
  636.                     MyUpdateEdition((*tempTS)->theSection);
  637.                     /* and indicate that this was saved with a document */
  638.                     (*(*tempTS)->theSection)->refCon |= kSavedOnce;     /* OR in our saved flag with type */
  639.                 }
  640.             }                                               /* text writeem if */
  641.             
  642.             if (dereg) {
  643.                 UnRegisterSection((SectionHandle)tempHandle);
  644.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  645.                 /* then we'll delete it.  */
  646.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
  647.                     OSErr myErr;
  648.                     FSSpec deleteSpec;
  649.                     Boolean myWasChanged;
  650.                     ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
  651.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  652.                         ShowMe("\pSection Save Delete Editon", myErr);
  653.                     }
  654.                 }
  655.                 
  656.                 /* and dispose of the alias handle */
  657.                 DisposeHandle((Handle)(*(SectionHandle)tempHandle)->alias);
  658.                 /* and the section handle */
  659.                 DisposeHandle((Handle)tempHandle);
  660.                 
  661.             }
  662.             tempTS = (*tempTS)->nextSection;
  663.         } while (tempTS);
  664.         
  665.     }
  666. }
  667.  
  668. /* MyCancelSection cancels this section.  It removes 
  669. *  the section info from our window structure, and also de-registers the
  670. * section with (from) the Edition Manager.  If it's a publisher, it also 
  671. * deletes the edition file 
  672. */
  673. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
  674. {
  675.     OSErr myErr;
  676.     windowCHandle shortName;
  677.     SectionHandle *tempPtr;
  678.     Rect *tempRectPtr;
  679.     register qq;
  680.     FSSpec deleteSpec;
  681.     Boolean myWasChanged;
  682.     shortName = (windowCHandle)GetWRefCon(theWindow);
  683.     HLock((Handle)shortName);
  684.     
  685.     /* first thing to do is deregister the thing */
  686.     UnRegisterSection(inSection);
  687.     if ((*inSection)->kind == stPublisher) {                /* only delete publishers */
  688.         ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
  689.         if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  690.             ShowMe("\pCancel Delete Editon", myErr);
  691.         }
  692.     }
  693.     /* get rid of the alias handle for it */
  694.     DisposeHandle((Handle)(*inSection)->alias);
  695.     if ((*inSection)->kind == stPublisher) {
  696.         HLock((*shortName)->pubs);                          /* lock down my list of section handles */
  697.         tempPtr = (SectionHandle *)*(*shortName)->pubs;
  698.         for (qq = 0; qq < (*shortName)->numPubs; qq++) {
  699.             HLock((Handle)*tempPtr);
  700.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  701.                 DisposeHandle((Handle)inSection);
  702.                 DisposeHandle((Handle)(*(*tempPtr))->alias);
  703.                 DisposeHandle((Handle)*tempPtr);
  704.                 HLock((*shortName)->pubRects);
  705.                 tempRectPtr = (Rect *)*((*shortName)->pubRects);
  706.                 tempRectPtr += qq;
  707.                 if (qq != (*shortName)->numPubs) {
  708.                     register ii;                            /* need to move information down */
  709.                     for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
  710.                         *tempPtr = *(tempPtr + 1);
  711.                         *tempRectPtr = *(tempRectPtr + 1);
  712.                         tempPtr += 1;
  713.                         tempRectPtr += 1;
  714.                     }
  715.                 }
  716.                 (*shortName)->numPubs--;
  717.                 HUnlock((*shortName)->pubs);
  718.                 MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
  719.                 HUnlock((*shortName)->pubRects);
  720.                 MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
  721.                 
  722.             }
  723.         }
  724.     } else {                                                /* it's a subscriber */
  725.         
  726.         HLock((*shortName)->subs);                          /* lock down my list of section handles */
  727.         tempPtr = (SectionHandle *)*(*shortName)->subs;
  728.         for (qq = 0; qq < (*shortName)->numSubs; qq++) {
  729.             
  730.             HLock((Handle)*tempPtr);
  731.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  732.                 SectionHandle removeSection;
  733.                 Handle *tempRectHand;
  734.                 Handle *tempPicHand;
  735.                 Handle *tempPicHand2;
  736.                 removeSection = (*tempPtr);
  737.                 HLock((Handle)removeSection);
  738.                 /* When the user cancels a subscription, you do NOT want to delete the */
  739.                 /* current subscription data (the picture) at this time.  Since the data should be */
  740.                 /* selectable in the document they are working on (text in a text doc, pic in a */
  741.                 /* pic doc, etc) they keep the last subscription data, and delete it */
  742.                 /* seperatly if they'd like */
  743.                 HLock((*shortName)->subRects);
  744.                 HLock((*shortName)->subDataHandle);
  745.                 tempRectHand = (Handle *)*((*shortName)->subRects);
  746.                 tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  747.                 tempRectHand += qq;
  748.                 tempPicHand += qq;
  749.                 
  750.                 /* move the picture over, increase the handle by 1 */
  751.                 (*shortName)->numPicts++;
  752.                 HUnlock((*shortName)->pictHandle);
  753.                 MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
  754.                 HLock((*shortName)->pictHandle);
  755.                 tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
  756.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  757.                 *tempPicHand2 = *tempPicHand;
  758.                 /* move the rect over also */
  759.                 HUnlock((*shortName)->pictRects);
  760.                 MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
  761.                 HLock((*shortName)->pictRects);
  762.                 tempPicHand2 = (Handle *)*(*shortName)->pictRects;
  763.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  764.                 *tempPicHand2 = *tempRectHand;
  765.                 HUnlock((*shortName)->pictRects);
  766.                 HUnlock((*shortName)->pictHandle);
  767.                 if ((qq + 1) != (*shortName)->numSubs) {
  768.                     register ii;                            /* need to move information down */
  769.                     for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
  770.                         *tempPtr = *(tempPtr + 1);
  771.                         *tempRectHand = *(tempRectHand + 1);
  772.                         *tempPicHand = *(tempPicHand + 1);
  773.                         tempPtr += 1;
  774.                         tempRectHand += 1;
  775.                         tempPicHand += 1;
  776.                     }
  777.                 }
  778.                 (*shortName)->numSubs--;
  779.                 HUnlock((*shortName)->subs);
  780.                 MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
  781.                 HUnlock((*shortName)->subRects);
  782.                 MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
  783.                 
  784.             }
  785.         }
  786.     }
  787.     HUnlock((Handle)shortName);
  788.     /* and clear the highlight */
  789.     if (gShowPub || gShowSub) {
  790.         extern Rect gShowPubRect;
  791.         extern Rect gShowSubRect;
  792.         extern SectionHandle gShowingSecHandle;
  793.         gShowPub = gShowSub = false;
  794.         gShowingSecHandle = nil;
  795.         InvalRect(&gShowPubRect);
  796.         InvalRect(&gShowSubRect);
  797.     }
  798. }
  799.  
  800. /* end MyCancelSection */
  801.  
  802. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
  803. {
  804.     OSErr myErr;
  805.     SectionHandle *tempPtr;
  806.     Handle *tempPicHand;
  807.     Size dataSize;
  808.     EditionRefNum sRefNum;
  809.     /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
  810.     /* them differently for drill. */
  811.     myErr = OpenEdition(secHandle, &sRefNum);
  812.     if (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))
  813.         (*secHandle)->refCon |= kTextType;
  814.     else
  815.         (*secHandle)->refCon |= kPictType;
  816.     /* Now that little mechanism could screw up, if the formats of the section have been */
  817.     /* changed since the subscription was originally created.  But it'll work here */
  818.     CloseEdition(sRefNum, true);
  819.     
  820.     /* increase our section handle holding handle by the size of a handle */
  821.     if (((*secHandle)->refCon & 0xf) == kPictType) {
  822.         HUnlock((*shortName)->subs);
  823.         MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
  824.         HLock((*shortName)->subs);
  825.         /* dereference the handle to our section handles in our window structure */
  826.         /* and cast it to a pointer to section handles, since that's what it contains */
  827.         tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
  828.         /* and store our subscriber section */
  829.         *tempPtr = (SectionHandle)secHandle;
  830.         HUnlock((*shortName)->subs);                        /* let it float again */
  831.         /* Here I'm setting up a handle for the picture data contained in the edition we just */
  832.         /* subscribed to, in an array of handles held in the handle subDataHandle  */
  833.         HUnlock((*shortName)->subDataHandle);
  834.         MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle));  /* allocate */
  835.         HLock((*shortName)->subDataHandle);
  836.         /* deref it */
  837.         tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  838.         tempPicHand += ((*shortName)->numSubs);
  839.         
  840.         if (pictIn == nil)
  841.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  842.         else
  843.             *tempPicHand = pictIn;
  844.         /* ••• NOTE:  You do _NOT_ read the data contained in this section yet! */
  845.         /* All you have done is subscribed to it, the Edition Manager has not told you */
  846.         /* that you can read it!  Wait for the section read event (see below) to get the */
  847.         /* data.  SO I store an empty handle here as a placeholder */
  848.         MoveHHi(*tempPicHand);
  849.         HUnlock((*shortName)->subRects);
  850.         MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle)));  /* allocate a new re*/
  851.         myErr = MemError();
  852.         if (myErr)
  853.             ShowMe("\pMemory error ", myErr);
  854.         HLock((*shortName)->subRects);
  855.         /* generate an empty display rectangle handle also */
  856.         tempPicHand = (Handle *)*((*shortName)->subRects);
  857.         tempPicHand += ((*shortName)->numSubs);
  858.         if (inRect == nil)
  859.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  860.         else
  861.             *tempPicHand = inRect;
  862.         MoveHHi(*tempPicHand);
  863.         (*shortName)->numSubs++;                            /* increment our count of subscribers */
  864.         HUnlock((*shortName)->subRects);
  865.         HUnlock((*shortName)->subDataHandle);
  866.     } else {
  867.         if (((*secHandle)->refCon & 0xf) == kTextType) {        /* double checking here */
  868.             textSectionHandle newSection;
  869.             /* get a new text section record */
  870.             if (inRect == nil) {
  871.                 /* this means that it is being created fresh, so we have to get a */
  872.                 /* text section record from my routine */
  873.                 newSection = GetTextSection(shortName, stSubscriber);
  874.                 /* fill it with stuff relating to the section we just created */
  875.                 (*newSection)->publishing = false;
  876.                 (*newSection)->theID = (*secHandle)->sectionID;
  877.                 (*newSection)->theSection = secHandle;
  878.             } else {
  879.                 newSection = (textSectionHandle)inRect;
  880.             }
  881.             /* store it in our window structure */
  882.             if ((*shortName)->textSections) {
  883.                 textSectionHandle tempSection = (*shortName)->textSections;
  884.                 if ((*shortName)->textSections) {
  885.                     while ((*tempSection)->nextSection)
  886.                         tempSection = (*tempSection)->nextSection;
  887.                 }
  888.                 (*tempSection)->nextSection = newSection;
  889.                 
  890.             } else {
  891.                 /* first one */
  892.                 (*shortName)->textSections = newSection;
  893.             }
  894.         }
  895.     }
  896. }
  897.  
  898. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
  899. {
  900.     short myHit;
  901.     short itemType;
  902.     ControlHandle theButton;
  903.     Rect theRect;
  904.     /* first make sure that a sub-dialog is not frontmost */
  905.     /* so we don't filter keys or hits to a sub-dialog */
  906.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  907.         /* first see if it's the 'first call' item (see the Standard File chapter).  If it is, then */
  908.         /* we preset our check box */
  909.         if (itemHit == -1) {
  910.             /* this gets the handle to our check box, since we know it's one past the last standard item */
  911.             GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  912.             SetControlValue(theButton, gResizeSub);             /* and set our current value */
  913.         } else {
  914.             /* only have one item in this expansion, but we'll check the range anyway to be safe */
  915.             myHit = itemHit - itemOffset;                   /* since our item numbers are relative to the total number */
  916.             /* of items in the dialog, and the system may change.  Always do your item numbering based */
  917.             /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
  918.             if (myHit == 1) {                               /* I only added one item, so this be the one */
  919.                 /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
  920.                 /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
  921.                 /* your custom items */
  922.                 GetDialogItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
  923.                 if (GetControlValue(theButton))
  924.                     gResizeSub = false;
  925.                 else
  926.                     gResizeSub = true;
  927.                 SetControlValue(theButton, gResizeSub);
  928.             }
  929.         }
  930.     }
  931.     return(itemHit);                                        /* the return value must be absolute */
  932. }
  933.  
  934. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
  935. {
  936.     short myHit;
  937.     short itemType;
  938.     ControlHandle theButton;
  939.     Rect theRect;
  940.     /* first make sure that a sub-dialog is not frontmost */
  941.     /* so we don't filter keys or hits to a sub-dialog */
  942.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  943.         /* standard filter proc kinda stuff here */
  944.         if ((theEvent->what) == keyDown) {
  945.             char tempChar;
  946.             tempChar = theEvent->message & charCodeMask;
  947.             
  948.             if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
  949.                 /* they pressed an A with the command key down, we get to handle it. */
  950.                 GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  951.                 if (GetControlValue(theButton))
  952.                     gResizeSub = false;
  953.                 else
  954.                     gResizeSub = true;
  955.                 SetControlValue(theButton, gResizeSub);
  956.                 return(true);                               /* tell folks we handled it */
  957.             }
  958.         }
  959.     }
  960.     return(false);                                          /* was not a keystroke we wanted */
  961.     
  962. }
  963.  
  964. /* DeleteSubscriber is called by a menu command 'Clear' */
  965.  
  966. void DeleteSubscriber(void)
  967. {
  968.     if (StopAlert(kCanxSub, nil) == 2) {
  969.         MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
  970.         
  971.     }
  972. }
  973.  
  974. /* end DeleteSubscriber */
  975.  
  976. /* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
  977. /* frontmost window (as you would expect) */
  978. void PasteSubscription(void)
  979. {
  980.     
  981.     windowCHandle tempWC;
  982.     SectionHandle tempHandle;
  983.     AliasHandle tempHandle2;
  984.     Handle tempRectHand;
  985.     FSSpec newFileSpec;
  986.     Boolean myWasChanged;
  987.     Rect tempPRect = {0,0,40,40};
  988.     long myOffset;
  989.     long fred;
  990.     PicHandle tempPicHandle;
  991.     tempRectHand = NewHandle(sizeof(Rect));
  992. /* first see if there is a section handle on the clipboard */
  993. /* kill the current section on the clipboard, if there is one */
  994. /* •••• NEW, we're looking for section handles and aliases on the clipboard.  */
  995.  
  996. /* set up a dummy picture for this incoming section.... */
  997.     if(!gScrapData)gScrapData=NewHandle(0);
  998.     fred=GetScrap(gScrapData, rSectionType, &myOffset);
  999.     if( fred > 0 ){
  1000.     myOffset=0;
  1001.     /* read in the rect also */
  1002.     fred = GetScrap(tempRectHand,'RECT',&myOffset);
  1003.     if(fred > 0 ){
  1004.     /* and read in the pict */
  1005.         myOffset=0;
  1006.     GetScrap((Handle)gClipPict,'PICT',&myOffset);
  1007.     }
  1008.     }
  1009.     HLock(tempRectHand);
  1010.     tempWC = (windowCHandle)GetWRefCon(gCurrentWindow);
  1011.     HLock((Handle)tempWC);
  1012.     if(gClipPict){*(Rect *)(*tempRectHand) = (*gClipPict)->picFrame;
  1013.     InvalRect(&(*gClipPict)->picFrame);                     /* make sure it gets drawn */
  1014.     } else {
  1015.     *(Rect *)(*tempRectHand)=tempPRect;
  1016.     }
  1017.     /* update the ID of the section to include the master ID of the window yer pasting into */
  1018.     (*gClipSection)->sectionID += (*tempWC)->windowID;
  1019.     StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
  1020.     HUnlock((Handle)tempWC);
  1021.     /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
  1022.     /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
  1023.     /* you could have two subscriptions with the same ID, which would not be nice.  So we do this... */
  1024.     tempHandle = gClipSection;
  1025.     tempHandle2 = (*gClipSection)->alias;
  1026.     HandToHand((Handle *)&tempHandle);
  1027.     HandToHand((Handle *)&tempHandle2);
  1028.     (*tempHandle)->sectionID = gSectionID;
  1029.     (*tempHandle)->alias = tempHandle2;
  1030.     gSectionID++;
  1031.     /* now register the section so the edition manager knows to send you updates */
  1032.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1033.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1034.         gClipSection = tempHandle;
  1035. //    gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1036.     gClipHasContents = kClipHasSub;
  1037.     MyReadSection(tempHandle);
  1038.     
  1039. }
  1040. /* CutSubscription and CopySubscription move the current selection in the active window to the */
  1041. /* ClipBoard.  The main difference here from standard scrap handling is that the scrap you now */
  1042. /* have is dynamic.  The contents of the clipboard can change if the publisher of this subscription */
  1043. /* changes, so you must treat this section as you would any other subscriber */
  1044. /* frontmost window (as you would expect) */
  1045. void CutSubscription(void)
  1046. {
  1047.     CopySubscription();
  1048.     DeleteSubscriber();                                     /* even though they said cut, I want to make sure that they really mean it */
  1049. }
  1050. /* CopySubscriber moves the current display subscriber to the clipboard, making a new */
  1051. /* subscription in the process, since we don't want to have two copies of the same thing */
  1052. void CopySubscription(void)
  1053. {
  1054.     SectionHandle tempHandle;
  1055.     AliasHandle tempHandle2;
  1056.     FSSpec newFileSpec;
  1057.     Boolean myWasChanged;
  1058.     /* First check to see if there is already a section to remove */
  1059.     if (gClipHasContents == kClipHasSub) {
  1060.         KillClipSub();
  1061.     }
  1062.     tempHandle = gShowingSecHandle;
  1063.     /* copy the alias also */
  1064.     tempHandle2 = (*gShowingSecHandle)->alias;
  1065.     HandToHand((Handle *)&tempHandle);
  1066.     HandToHand((Handle *)&tempHandle2);
  1067.     /* create a unique ID for this section.  I'll just use the next section ID */
  1068.     (*tempHandle)->sectionID = gSectionID;
  1069.     (*tempHandle)->alias = tempHandle2;
  1070.     gSectionID++;
  1071.     /* now register the section so the edition manager knows to send you updates */
  1072.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1073.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1074.         gClipSection = tempHandle;
  1075.     gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1076.     gClipHasContents = kClipHasSub;
  1077. /* write the section handle out to the cipboard */
  1078.       ZeroScrap();
  1079.         PutScrap(sizeof(Handle),rSectionType,(Ptr)&tempHandle);
  1080.         PutScrap(sizeof(Rect),'RECT',(Ptr)&gShowSubRect);
  1081.         
  1082.     MyReadSection(tempHandle);
  1083.     
  1084.     InitCursor();                                           /* set to watch by MyReadSection, would normally be reset next pass */
  1085.     /* through the event loop, but NOT if it's being called by Cut, */
  1086.     /* so I'll reset it just to be safe */
  1087. }
  1088.  
  1089. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
  1090. {
  1091.     extern Handle gScrapData;
  1092.     WindowPtr temp;
  1093.     MySetHandleSize((Handle)gClipPict, readIn);
  1094.     HLock((Handle)gClipPict);
  1095.     /* read the pict in */
  1096.     MyReadEditionData((Ptr)*gClipPict, 'PICT', sRefNum, &readIn);
  1097.     HUnlock((Handle)gClipPict);
  1098.     gScrapData = (Handle)gClipPict;
  1099.     if (((WindowPeek)gClipWindowPtr)->visible) {
  1100.         WindowPtr temp;
  1101.         GetPort(&temp);
  1102.         SetPort(gClipWindowPtr);
  1103.         InvalRect(&gClipWindowPtr->portRect);
  1104.         SetPort(temp);
  1105.     }
  1106. }
  1107. /* This kills the current section on the clipboard, since it's being replaced */
  1108. /* and you don't want to receive events for it anymore */
  1109. void KillClipSub(void)
  1110. {
  1111.     UnRegisterSection(gClipSection);
  1112.     DisposeHandle((Handle)(*gClipSection)->alias);
  1113.     DisposeHandle((Handle)gClipSection);
  1114.     gClipSection = nil;
  1115.     gClipHasContents = kClipEmpty;
  1116.     if (GetHandleSize((Handle)gClipPict) != nil)
  1117.         KillPicture(gClipPict);
  1118. }
  1119.  
  1120. /* MyGoToPublisher is used if the user was holding down the Option key during a */
  1121. /* double click, to send them to the publisher without seeing the dialog box */
  1122. OSErr MyGoToPublisher(SectionHandle theSection)
  1123. {
  1124.     EditionInfoRecord theEdInfo;
  1125.     
  1126.     GetEditionInfo(theSection, &theEdInfo);
  1127.     GoToPublisherSection(&theEdInfo.container);
  1128. }
  1129.  
  1130.  
  1131. #undef __SUBSCRIBE__
  1132.